package com.pp.third.remote.service;

import com.alibaba.fastjson.JSON;
import com.pp.third.remote.feign.ThirdAuthFeignService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;

import java.util.Map;

/**
 * 自定义FeignTokenService
 *
 * 该接口通过feign调用check_token,绕过nginx和gateway;降低check_token响应耗时
 *
 * @author pp
 * @date 2022/12/13 2:03 下午
 */
@Slf4j
public class CustomeFeignTokenServices implements ResourceServerTokenServices {

    private AccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();

    private ThirdAuthFeignService thirdAuthFeignService;


    public CustomeFeignTokenServices() {
    }

    public void setAccessTokenConverter(AccessTokenConverter accessTokenConverter) {
        this.tokenConverter = accessTokenConverter;
    }

    @SneakyThrows
    @Override
    public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException {
        // 调用checkToken异常,返回401
        Map<String, Object> map = null;

        // 检查token是否为空
        if (StringUtils.isBlank(accessToken)){
            throw new RuntimeException("check_token fail token is null");
        }

        try {
            Long startTime = System.currentTimeMillis();
            map = thirdAuthFeignService.checkToken(accessToken);
            log.info("feign request info url:[{}] time:[{}]","oauth/check_token",System.currentTimeMillis() - startTime);
        }catch (Exception e){
            //log.error(e.getMessage(), e);
            if (null != map){
                log.error("check_token returned error:{} token:{} ",JSON.toJSONString(map), accessToken);
            }
            throw new RuntimeException("check_token fail token:" + accessToken,e);
        }

        if (map.containsKey("error")) {
            log.warn("check_token returned error: token:{}",JSON.toJSONString(map), accessToken);
            throw new InvalidTokenException(accessToken);
        } else if (!Boolean.TRUE.equals(map.get("active"))) {
            log.info("check_token returned active attribute:{} ",map.get("active"));
            throw new InvalidTokenException(accessToken);
        } else {
            return this.tokenConverter.extractAuthentication(map);
        }
    }

    @Override
    public OAuth2AccessToken readAccessToken(String accessToken) {
        throw new UnsupportedOperationException("Not supported: read access token");
    }

    public void setThirdAuthFeignService(ThirdAuthFeignService thirdAuthFeignService) {
        this.thirdAuthFeignService = thirdAuthFeignService;
    }

}